#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

extern unsigned long volatile page_fault_count;

char *msg; // 缓冲区
int read_page_fault_count(struct file *filp, char *buf, size_t count, loff_t *offp)
{
    if (*offp != 0)
    {
        // 初始偏移量为0
        // 如果偏移量不为0, 则说明已经读取过了
        // 结束
        return 0;
    }
    sprintf(msg, "%ld\n", page_fault_count);
    int len = strlen(msg);
    copy_to_user(buf, msg, len);
    *offp += len; // 增加偏移量
    return len;
}

struct file_operations fops = {
    read : read_page_fault_count,
};

static int page_fault_init(void)
{
    // 注册proc
    struct proc_dir_entry *file = proc_create("page_fault_count", 0, NULL, &fops);
    if (file == NULL)
    {
        printk("page_fault.ko: create_proc_entry failed\n");
        return 1;
    }

    // 分配内核态缓冲区
    msg = kmalloc(20 * sizeof(char), GFP_ATOMIC);
    if (msg == NULL)
    {
        printk("page_fault.ko: kmalloc failed\n");
        return 1;
    }

    printk("page_fault.ko: proc_entry successfully\n");
    return 0;
}

static void page_fault_exit(void)
{
    // 移除proc
    remove_proc_entry("page_fault_count", NULL);
    // 释放缓冲区
    kfree(msg);
}

MODULE_LICENSE("GPL");

module_init(page_fault_init);
module_exit(page_fault_exit);
